package com.hunter.service;

import com.alibaba.fastjson.JSON;
import gnu.io.*;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.*;

@Component
public class RXTXService extends Observable implements Runnable,SerialPortEventListener {

    static CommPortIdentifier portId;
    int delayRead = 100;
    int numBytes; // buffer中的实际数据字节数
    private static byte[] readBuffer = new byte[4096]; // 4k的buffer空间,缓存串口读入的数据
    InputStream inputStream;
    static SerialPort serialPort;
    HashMap serialParams;

    //端口是否打开了
    boolean isOpen = false;
    // 端口读入数据事件触发后,等待n毫秒后再读取,以便让数据一次性读完
    public static final String PARAMS_DELAY = "delay read"; // 延时等待端口数据准备的时间
    public static final String PARAMS_TIMEOUT = "timeout"; // 超时时间
    public static final String PARAMS_PORT = "port name"; // 端口名称
    public static final String PARAMS_DATABITS = "data bits"; // 数据位
    public static final String PARAMS_STOPBITS = "stop bits"; // 停止位
    public static final String PARAMS_PARITY = "parity"; // 奇偶校验
    public static final String PARAMS_RATE = "rate"; // 波特率

    public RXTXService()
    {
        isOpen = false;
    }

    public void open(HashMap params) {
        serialParams = params;
        if(isOpen){
            System.out.println("端口使用中");
            close();
        }
        try {
            System.out.println("配置参数");
            // 参数初始化
            int timeout = Integer.parseInt( serialParams.get( PARAMS_TIMEOUT ).toString() );
            int rate = Integer.parseInt( serialParams.get( PARAMS_RATE ).toString() );
            int dataBits = Integer.parseInt( serialParams.get( PARAMS_DATABITS ).toString() );
            int stopBits = Integer.parseInt( serialParams.get( PARAMS_STOPBITS ).toString() );
            int parity = Integer.parseInt( serialParams.get( PARAMS_PARITY ).toString() );
            delayRead = Integer.parseInt( serialParams.get( PARAMS_DELAY ).toString() );
            String port = serialParams.get( PARAMS_PORT ).toString();
            System.out.println("准备打开端口");
            // 打开端口
            portId = CommPortIdentifier.getPortIdentifier( port );
            serialPort = ( SerialPort ) portId.open( "SerialReader", timeout );
            System.out.println("打开完毕");
            inputStream = serialPort.getInputStream();
            serialPort.addEventListener( this );
            serialPort.notifyOnDataAvailable( true );
            serialPort.setSerialPortParams( rate, dataBits, stopBits, parity );

            isOpen = true;
        } catch ( PortInUseException e ) {
            // 端口"+serialParams.get( PARAMS_PORT ).toString()+"已经被占用";
        } catch ( TooManyListenersException e ) {
            //"端口"+serialParams.get( PARAMS_PORT ).toString()+"监听者过多";
        } catch ( UnsupportedCommOperationException e ) {
            //"端口操作命令不支持";
        } catch ( NoSuchPortException e ) {
            //"端口"+serialParams.get( PARAMS_PORT ).toString()+"不存在";
        } catch ( IOException e ) {
            //"打开端口"+serialParams.get( PARAMS_PORT ).toString()+"失败";
        }
        serialParams.clear();
        Thread readThread = new Thread( this );
        readThread.start();
    }


    public void run() {
        try {
            Thread.sleep(50);
        } catch ( InterruptedException e ) {

        }
    }


    public void close() {
        if (isOpen) {
            try {
                serialPort.notifyOnDataAvailable(false);
                serialPort.removeEventListener();
                inputStream.close();
                serialPort.close();
                isOpen = false;
            } catch (IOException ex) {
                //"关闭串口失败";
            }
        }
    }

    public void serialEvent( SerialPortEvent event ) {
        try {
            Thread.sleep( 1000 );
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        }
        System.out.println("getEventType");
        switch ( event.getEventType() ) {
            case SerialPortEvent.DATA_AVAILABLE: // 1
                try {
                    readSMS();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            break;
        }
    }

    public void readSMS() throws IOException {
        System.out.println("监听到有效数据");
        try {
            Thread.sleep( 1000 );
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        }
        try {
            // 多次读取,将所有数据读入
            Arrays.fill(readBuffer, (byte)0);
            while (inputStream.available() > 0) {
                numBytes = inputStream.read(readBuffer);
                System.out.println("读取到-"+numBytes+"-个字节");
            }
            String smsStr = new String(readBuffer,"gbk");
            Arrays.fill(readBuffer,(byte) 0);
            System.out.println("读取到的内容usf-8编码"+smsStr);
            String deCodeStr = URLDecoder.decode(smsStr, "utf-8");
            System.out.println("内容解压后："+deCodeStr);
            deCodeStr = deCodeStr.trim().replaceAll("[(]","{").replaceAll("[)]","}").replaceAll("\\u001B","");
            System.out.println("读取到短信:"+deCodeStr);
            Map<String,Object> params = new HashMap<>();
            if(deCodeStr.toLowerCase().startsWith("hz")){
                if(deCodeStr.toLowerCase().startsWith("hz01") || deCodeStr.toLowerCase().startsWith("hz02") || deCodeStr.toLowerCase().startsWith("hz03")
                        || deCodeStr.toLowerCase().startsWith("hz04") || deCodeStr.toLowerCase().startsWith("hz05")){
                    System.out.println(deCodeStr);
                    params.put("mark", deCodeStr.split(",")[0]);
                    params.put("data", deCodeStr.substring(deCodeStr.indexOf(",")+1));
                }
            }else{
                params = (Map) JSON.parse(deCodeStr);
            }

            //关键逻辑，调用httpClient 把短信发送到报警端
            HttpClientUtils.get(params);
        } catch ( IOException e ) {
            e.printStackTrace();
        }
    }

    public void openSerialPort() {
        HashMap<String, Comparable> params = new HashMap<String, Comparable>();
        String port="/dev/ttyUSB0";//linux环境下的串口名称
        //String port="COM4";//windows下的串口名称
        String rate = "9600";
        String dataBit = ""+SerialPort.DATABITS_8;
        String stopBit = ""+SerialPort.STOPBITS_2;
        String parity = ""+SerialPort.PARITY_NONE;
        int parityInt = SerialPort.PARITY_NONE;
        params.put( RXTXService.PARAMS_PORT, port ); // 端口名称
        params.put( RXTXService.PARAMS_RATE, rate ); // 波特率
        params.put( RXTXService.PARAMS_DATABITS,dataBit  ); // 数据位
        params.put( RXTXService.PARAMS_STOPBITS, stopBit ); // 停止位
        params.put( RXTXService.PARAMS_PARITY, parityInt ); // 无奇偶校验
        params.put( RXTXService.PARAMS_TIMEOUT, 2000 ); // 设备超时时间 1秒
        params.put( RXTXService.PARAMS_DELAY, 2000 ); // 端口数据准备时间 1秒
        try {
            open(params);//打开串口
            System.out.println("串口打开");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static String getPortTypeName( int portType ) {
        switch ( portType ) {
            case CommPortIdentifier.PORT_I2C:
                return "I2C";
            case CommPortIdentifier.PORT_PARALLEL:
                return "Parallel";
            case CommPortIdentifier.PORT_RAW:
                return "Raw";
            case CommPortIdentifier.PORT_RS485:
                return "RS485";
            case CommPortIdentifier.PORT_SERIAL:
                return "Serial";
            default:
                return "unknown type";
        }
    }


    public  HashSet<CommPortIdentifier> getAvailableSerialPorts() {//本来static

        HashSet<CommPortIdentifier> h = new HashSet<CommPortIdentifier>();
        Enumeration thePorts = CommPortIdentifier.getPortIdentifiers();
        while ( thePorts.hasMoreElements() ) {
            CommPortIdentifier com = ( CommPortIdentifier ) thePorts
                    .nextElement();
            switch ( com.getPortType() ) {
                case CommPortIdentifier.PORT_SERIAL:
                    try {
                        CommPort thePort = com.open( "CommUtil", 50 );
                        thePort.close();
                        h.add( com );
                    } catch ( PortInUseException e ) {
                        System.out.println( "Port, " + com.getName() + ", is in use." );
                    } catch ( Exception e ) {
                        System.out.println( "Failed to open port " + com.getName() + e );
                    }
            }
        }
        return h;
    }

//    public static void main(String[] args) throws InterruptedException {
//    }
}